# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner --aarch64postlegalizercombinerhelper-only-enable-rule="bitfield_extract_from_and" -verify-machineinstrs %s -o - | FileCheck %s
# REQUIRES: asserts

# Check that we can combine
#
# and (lshr x, cst), mask -> ubfx x, cst, width

...
---
name:            ubfx_s32
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $w0

    ; LSB = 5
    ; Width = LSB + trailing_ones(255) - 1 =
    ;         5 + 8 - 1 = 12

    ; CHECK-LABEL: name: ubfx_s32
    ; CHECK: liveins: $w0
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %lsb:_(s32) = G_CONSTANT i32 5
    ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
    ; CHECK: %and:_(s32) = G_UBFX %x, %lsb(s32), [[C]]
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %lsb:_(s32) = G_CONSTANT i32 5
    %mask:_(s32) = G_CONSTANT i32 255
    %shift:_(s32) = G_LSHR %x, %lsb
    %and:_(s32) = G_AND %shift, %mask
    $w0 = COPY %and
    RET_ReallyLR implicit $w0

...
---
name:            ubfx_s64
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $x0

    ; LSB = 5
    ; Width = LSB + trailing_ones(1) - 1 =
    ;         5 + 1 - 1 = 5

    ; CHECK-LABEL: name: ubfx_s64
    ; CHECK: liveins: $x0
    ; CHECK: %x:_(s64) = COPY $x0
    ; CHECK: %lsb:_(s64) = G_CONSTANT i64 5
    ; CHECK: %mask:_(s64) = G_CONSTANT i64 1
    ; CHECK: %and:_(s64) = G_UBFX %x, %lsb(s64), %mask
    ; CHECK: $x0 = COPY %and(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s64) = COPY $x0
    %lsb:_(s64) = G_CONSTANT i64 5
    %mask:_(s64) = G_CONSTANT i64 1
    %shift:_(s64) = G_LSHR %x, %lsb
    %and:_(s64) = G_AND %shift, %mask
    $x0 = COPY %and
    RET_ReallyLR implicit $x0

...
---
name:            dont_combine_no_and_cst
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $w0, $w1

    ; UBFX needs to be selected to UBFMWri/UBFMXri, so we need constants.

    ; CHECK-LABEL: name: dont_combine_no_and_cst
    ; CHECK: liveins: $w0, $w1
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %y:_(s32) = COPY $w1
    ; CHECK: %lsb:_(s32) = G_CONSTANT i32 5
    ; CHECK: %shift:_(s32) = G_LSHR %x, %lsb(s32)
    ; CHECK: %and:_(s32) = G_AND %shift, %y
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %lsb:_(s32) = G_CONSTANT i32 5
    %shift:_(s32) = G_LSHR %x, %lsb
    %and:_(s32) = G_AND %shift, %y
    $w0 = COPY %and
    RET_ReallyLR implicit $w0

...
---
name:            dont_combine_and_cst_not_mask
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $w0
    ; CHECK-LABEL: name: dont_combine_and_cst_not_mask
    ; CHECK: liveins: $w0
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %lsb:_(s32) = G_CONSTANT i32 5
    ; CHECK: %not_a_mask:_(s32) = G_CONSTANT i32 2
    ; CHECK: %shift:_(s32) = G_LSHR %x, %lsb(s32)
    ; CHECK: %and:_(s32) = G_AND %shift, %not_a_mask
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %lsb:_(s32) = G_CONSTANT i32 5
    %not_a_mask:_(s32) = G_CONSTANT i32 2
    %shift:_(s32) = G_LSHR %x, %lsb
    %and:_(s32) = G_AND %shift, %not_a_mask
    $w0 = COPY %and
    RET_ReallyLR implicit $w0

...
---
name:            dont_combine_shift_more_than_one_use
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $x0
    ; CHECK-LABEL: name: dont_combine_shift_more_than_one_use
    ; CHECK: liveins: $x0
    ; CHECK: %x:_(s64) = COPY $x0
    ; CHECK: %lsb:_(s64) = G_CONSTANT i64 5
    ; CHECK: %mask:_(s64) = G_CONSTANT i64 1
    ; CHECK: %shift:_(s64) = G_LSHR %x, %lsb(s64)
    ; CHECK: %and:_(s64) = G_AND %shift, %mask
    ; CHECK: %sub:_(s64) = G_SUB %and, %shift
    ; CHECK: $x0 = COPY %sub(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s64) = COPY $x0
    %lsb:_(s64) = G_CONSTANT i64 5
    %mask:_(s64) = G_CONSTANT i64 1
    %shift:_(s64) = G_LSHR %x, %lsb
    %and:_(s64) = G_AND %shift, %mask
    %sub:_(s64) = G_SUB %and, %shift
    $x0 = COPY %sub
    RET_ReallyLR implicit $x0

...
---
name:            dont_combine_negative_lsb
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $w0

    ; LSB must be in [0, reg_size)

    ; CHECK-LABEL: name: dont_combine_negative_lsb
    ; CHECK: liveins: $w0
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %negative:_(s32) = G_CONSTANT i32 -1
    ; CHECK: %mask:_(s32) = G_CONSTANT i32 255
    ; CHECK: %shift:_(s32) = G_LSHR %x, %negative(s32)
    ; CHECK: %and:_(s32) = G_AND %shift, %mask
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %negative:_(s32) = G_CONSTANT i32 -1
    %mask:_(s32) = G_CONSTANT i32 255
    %shift:_(s32) = G_LSHR %x, %negative
    %and:_(s32) = G_AND %shift, %mask
    $w0 = COPY %and
    RET_ReallyLR implicit $w0

...
---
name:            dont_combine_lsb_too_large
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $w0

    ; LSB must be in [0, reg_size)

    ; CHECK-LABEL: name: dont_combine_lsb_too_large
    ; CHECK: liveins: $w0
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %too_large:_(s32) = G_CONSTANT i32 32
    ; CHECK: %mask:_(s32) = G_CONSTANT i32 255
    ; CHECK: %shift:_(s32) = G_LSHR %x, %too_large(s32)
    ; CHECK: %and:_(s32) = G_AND %shift, %mask
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %too_large:_(s32) = G_CONSTANT i32 32
    %mask:_(s32) = G_CONSTANT i32 255
    %shift:_(s32) = G_LSHR %x, %too_large
    %and:_(s32) = G_AND %shift, %mask
    $w0 = COPY %and
    RET_ReallyLR implicit $w0

...
---
name:            dont_combine_vector
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $d0
    ; CHECK-LABEL: name: dont_combine_vector
    ; CHECK: liveins: $d0
    ; CHECK: %x:_(<2 x s32>) = COPY $d0
    ; CHECK: %lsb_cst:_(s32) = G_CONSTANT i32 5
    ; CHECK: %lsb:_(<2 x s32>) = G_BUILD_VECTOR %lsb_cst(s32), %lsb_cst(s32)
    ; CHECK: %mask_cst:_(s32) = G_CONSTANT i32 255
    ; CHECK: %mask:_(<2 x s32>) = G_BUILD_VECTOR %mask_cst(s32), %mask_cst(s32)
    ; CHECK: %shift:_(<2 x s32>) = G_LSHR %x, %lsb(<2 x s32>)
    ; CHECK: %and:_(<2 x s32>) = G_AND %shift, %mask
    ; CHECK: $d0 = COPY %and(<2 x s32>)
    ; CHECK: RET_ReallyLR implicit $d0
    %x:_(<2 x s32>) = COPY $d0
    %lsb_cst:_(s32) = G_CONSTANT i32 5
    %lsb:_(<2 x s32>) = G_BUILD_VECTOR %lsb_cst, %lsb_cst
    %mask_cst:_(s32) = G_CONSTANT i32 255
    %mask:_(<2 x s32>) = G_BUILD_VECTOR %mask_cst, %mask_cst
    %shift:_(<2 x s32>) = G_LSHR %x, %lsb
    %and:_(<2 x s32>) = G_AND %shift, %mask
    $d0 = COPY %and
    RET_ReallyLR implicit $d0

...
---
name:            max_signed_int_mask
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $x0
    ; mask = 0111 1111 1111 ... 1111
    ; mask + 1 = 1000 0000 0000 ... 0000
    ; CHECK-LABEL: name: max_signed_int_mask
    ; CHECK: liveins: $x0
    ; CHECK: %x:_(s64) = COPY $x0
    ; CHECK: %lsb:_(s64) = G_CONSTANT i64 0
    ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 63
    ; CHECK: %and:_(s64) = G_UBFX %x, %lsb(s64), [[C]]
    ; CHECK: $x0 = COPY %and(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s64) = COPY $x0
    %lsb:_(s64) = G_CONSTANT i64 0
    %mask:_(s64) = G_CONSTANT i64 9223372036854775807
    %shift:_(s64) = G_LSHR %x, %lsb
    %and:_(s64) = G_AND %shift, %mask
    $x0 = COPY %and
    RET_ReallyLR implicit $x0

...
---
name:            max_unsigned_int_mask
tracksRegLiveness: true
legalized: true
body:             |
  bb.0:
    liveins: $x0
    ; mask = 1111 1111 1111 ... 1111
    ; mask + 1 = 0000 0000 0000 ... 000
    ; CHECK-LABEL: name: max_unsigned_int_mask
    ; CHECK: liveins: $x0
    ; CHECK: %x:_(s64) = COPY $x0
    ; CHECK: %lsb:_(s64) = G_CONSTANT i64 5
    ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
    ; CHECK: %and:_(s64) = G_UBFX %x, %lsb(s64), [[C]]
    ; CHECK: $x0 = COPY %and(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s64) = COPY $x0
    %lsb:_(s64) = G_CONSTANT i64 5
    %mask:_(s64) = G_CONSTANT i64 18446744073709551615
    %shift:_(s64) = G_LSHR %x, %lsb
    %and:_(s64) = G_AND %shift, %mask
    $x0 = COPY %and
    RET_ReallyLR implicit $x0
